// blocks containing SIYUAN scanned

#ifndef _DDMCMC_MEANSHIFT
#define _DDMCMC_MEANSHIFT

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;
using namespace std;

const int	p_max = 3;	// max space dim;  MAX(p_max) == 6 !!

// From mcRasterColor.h
#define nil				0
#define Max_rects		50

#define Lightness		(1<<3)
#define Ustar   		(1<<4)
#define Vstar   		(1<<5)

typedef struct region_str
{
	int my_contor;
	int my_class;
	int my_label;
	int *my_region;
	struct region_str *next_region_str;
}REGION;


class DDMCMC_MeanShiftClustering{
public:
	DDMCMC_MeanShiftClustering(Mat mOriginalImg);
	~DDMCMC_MeanShiftClustering();

private:
	struct sRectangle
	{
		int x, y;							// upper left corner
		unsigned int width, height;	        // rectangle dimensions
	};

	bool	ms_segment(Rect*, int, int, unsigned int, bool, int nOption = 2);
	//inline  mcmcMatrix<int>& GetLabels(void){ return ImageLabels; };
	//void	RunMeanshift(void);


// SIYUAN
private:
	Mat mImg_RGB, /*mImg_BGR,*/ mImg_LUV, mImg_LUV_CV8UC3;
	int nRows, nCols, count;

public:
	void meanShiftSegmentation(int nOption);
	inline Mat getLabels(){ return ImageLabels.clone(); };
	inline Mat getClusteredImage(){ return mImg_RGB.clone(); };

protected:

	int		_k;						// parameter space dimension
	int		_comp_cnt;				// counter for the number of components already
	// stored in _data_all
	int		option;					// 0: over segmentation 1: 2:

	int**   _data;					// region of the input data currently segmented
	int		_rg_rows, _rg_colms;	// width, height dimensions of the region
	int		_rg_cnt;				// number of data points (per channel)
	double	_min_per;				// minimum/maximum cluster size
	int		_max_sub_samp;			// maximum number of subsamples
	bool	auto_segm;
	int*    _remn_cnt_map;			//the map of remaining points
	uchar*  _labels;				//labels, the class that every pixel belong to
	uchar*  taken;
	int*    conn_selected;			//used by connected component
	int		_remn_cnt;				//# of remaining points

	void	cut_rectangle(Rect*);
	void	init_matr(void);
	double	my_sampling(int, double T[Max_rects][p_max]);
	int		subsample(double*);
	void	test_neigh(uchar*, int *, int*, int);
	void	my_actual(uchar*);
	void	init_neigh(void);
	void	conn_comp(uchar *, int*, uchar*, double[][p_max], int, int);
	void	find_other_neigh(int, int *, REGION *);
	void	new_auto_loop(double *, uchar*);
	void	nauto_loop(double *, int *, uchar *, int *);
	void	optimize(double[][p_max], int);
	void	get_codeblock(double[][p_max], int);
	void	get_codeblock1(double[][p_max], int);
	void	new_codebook(double[][p_max], int);
	void	my_clean(double[][p_max], int);
	void	eliminate_class(uchar *, int *, int *, int, uchar *, double[][p_max], REGION *);
	void	eliminate_region(int *, int, double[][p_max], REGION *);
	void	destroy_region_list(REGION *);
	REGION *create_region_list(int *, int);
	void	initializations(Rect[], int *, int, int *);

	//void	SetHistogram(void);
	//void	SetInitSeeds(const int k);

private:
	Mat ImageLabels;
	//mcmcMatrix<int>			ImageLabels;

	int					min_l, min_u, min_v;
	int					max_l, max_u, max_v;

	void    mean_s(const int N, const int p, int J[], int **data, double T[]);
	void    covariance_w(const int N, int M, const int p, int ** data,
		int *w, double T[], double C[p_max][p_max]);
	void    reverse_map(uchar *, uchar *, int *, uchar *, double T[][p_max]);
	void	set_RADIUS(int color_cnt, int final);
	int		test_same_cluster(int rect, double T[][p_max]);


// SIYUAN: The following variables and functions are from mcRasterColor.h
	int          _n_colors;      //# of colors
	int**       _col_all;       //colors in the image (LUV)
	int*		_col0, *_col1, *_col2;      //to speed up
	int*		_col_RGB;       //colors in the image (RGB)
	int*        _col_index;     //color address
	int*        _col_misc;      //misc use in histogram and conversion
	int*        _m_colors;      //how many of each color
	int*        _col_remain;    //the map of remaining colors
	int*        _m_col_remain;  //table of remaining colors
	int         _n_col_remain;  //# of remaining colors

	double color_dis(const int row, const int col, const double mean_L, const double mean_U, const double mean_V);
	double color_dis(const int index, const double mean_L, const double mean_U, const double mean_V);
	void CreateLUVspace();
	void Free_histogram_space();
	void histogram(int selects = Lightness | Ustar | Vstar);
	void convert_LUV_RGB(double *pLUV, int *pRGB, int selects);
	void convert_RGB_LUV(int selects = Lightness | Ustar | Vstar);
	int	ShiftColorValues(const int index);
	//int color_dis(const int index, const double mean_L, const double mean_U, const double mean_V);
	
};


// Implementation of some helper functions from mcRasterColor.h

// Accessing functions
/*
// mImg_BGR.at<Vec3b>(index/nCols, index%nCols).val[2];
// mImg_BGR.at<Vec3b>(k/nCols, k%nCols).val[2];
uchar DDMCMC_MeanShiftClustering::R(int index){ 
	int x = index % nCols;
	int y = index / nCols;
	return mImg_BGR.at<Vec3b>(y, x).val[2];
}

// mImg_BGR.at<Vec3b>(index/nCols, index%nCols).val[1];
// mImg_BGR.at<Vec3b>(k/nCols, k%nCols).val[1];
uchar DDMCMC_MeanShiftClustering::G(int index){
	int x = index % nCols;
	int y = index / nCols;
	return mImg_BGR.at<Vec3b>(y, x).val[1];
}

// mImg_BGR.at<Vec3b>(index/nCols, index%nCols).val[0];
// mImg_BGR.at<Vec3b>(k/nCols, k%nCols).val[0];
uchar DDMCMC_MeanShiftClustering::B(int index){
	int x = index % nCols;
	int y = index / nCols;
	return mImg_BGR.at<Vec3b>(y, x).val[0];
}

// mImg_LUV.at<Vec3s>(index/nCols, index%nCols).val[0];
// mImg_LUV.at<Vec3s>(k/nCols, k%nCols).val[0];
uchar DDMCMC_MeanShiftClustering::L(int index){
	int x = index % nCols;
	int y = index / nCols;
	return mImg_LUV.at<Vec3s>(y, x).val[0];
}

// mImg_LUV.at<Vec3s>(index/nCols, index%nCols).val[1];
// mImg_LUV.at<Vec3s>(k/nCols, k%nCols).val[1];
uchar DDMCMC_MeanShiftClustering::U(int index){
	int x = index % nCols;
	int y = index / nCols;
	return mImg_LUV.at<Vec3s>(y, x).val[1];
}

// mImg_LUV.at<Vec3s>(index/nCols, index%nCols).val[2];
// mImg_LUV.at<Vec3s>(k/nCols, k%nCols).val[2];
uchar DDMCMC_MeanShiftClustering::V(int index){
	int x = index % nCols;
	int y = index / nCols;
	return mImg_LUV.at<Vec3s>(y, x).val[2];
}
*/

#endif
